import express from 'express';
import path from 'path';
import fs from 'fs';
import policies from '../policies/index.js';

/**
 * Dynamics import api controllers.
 * @param {*} r express Router
 * @returns Function<Array>: viod
 */
const _createRouter = (r) => {
  return routes => {
    Object.keys(routes).forEach(async key => {
      const item = routes[key];
      const middlewares = [];

      // policies
      if(Array.isArray(item.policies)) {
        item.policies.forEach(police => {
          if(typeof policies[police] === 'function') {
            middlewares.push(policies[police]);
          }
        })
      }

      // Save middleware.
      if(Array.isArray(item.middlewares)) {
        item.middlewares.forEach(async item => {
          const p = '../middleware/' + item + '.js';
          const ware = await import(p);
          const wareFn = ware.default;
          if(typeof wareFn === 'function') {
            middlewares.push(wareFn);
          }
        })
      }

      const restful = r[item.method.toLocaleLowerCase()];
      const ctrlPath = item.controller.split('.');
      const p = '../controller/' + ctrlPath.slice(0,-1).join('/') + '.js';
      const controller = await import(p);
      const c = controller[ctrlPath.slice(-1)];

      if(c) {
        restful.apply(r, [key, ...middlewares, c]);
      }
    });
  }
}

// Read all router config in modules dir.
const readAllRoutes = (callback, modulePath = 'modules') => {
  try {
    const jsonFiles = fs.readdirSync(path.resolve(process.cwd(), `./dist/routes/${modulePath}`));

    // Dynamics import router config files;
    // And use 'creatByRoutes' generation routes.
    jsonFiles.forEach(async file => {
      const filePath = `../routes/${modulePath}/` + file;
      const r = await import(filePath);
      callback(r.default)
    });
  } catch (error) {
    console.log(error);
  }
}

export default function createRouter(modulePath) {
    const router = express.Router();

    // Create function use by modules router config.
    const createByRoutes = _createRouter(router);
    // Generation routes.
    readAllRoutes(routes => createByRoutes(routes), modulePath);
    return router;
}
